using System;
using System.Collections.Generic;
using Me.Prettyprint.Cassandra.Connection.Factory;
using Me.Prettyprint.Cassandra.Service;

namespace Me.Prettyprint.Cassandra.Connection
{
    /// <summary>
    /// The balancing policy simply gets a connection in a round-robin fashion. Basically,
    /// it loops through the list of pools and just gets the next one. For example, if there's
    /// 3 nodes in the ring, it will go 1, 2, 3, 1, 2, 3. Over time the traffic should be
    /// close to even assuming there isn't a hot node.
    /// </summary>
	[Serializable]
	public class RoundRobinBalancingPolicy : LoadBalancingPolicy
	{
        private Me.Prettyprint.Cassandra.Utils.Logger logger = new Me.Prettyprint.Cassandra.Utils.Logger(typeof(RoundRobinBalancingPolicy));
		private int counter;
		
		public RoundRobinBalancingPolicy()
		{
			counter = 0;
		}
		private int getAndIncrement(int size)
		{
			int counterToReturn;
			
			// There should not be that much of contention here as
			// the "if" statement plus the increment is executed real fast.
			lock (this)
			{
                if (counter >= 16384)
				{
					counter = 0;
				}
				counterToReturn = counter++;
			}
			
			return counterToReturn % size;
		}
        public virtual HClientPool GetPool(ICollection<HClientPool> pools, List<CassandraHost> excludeHosts)
        {
            Dictionary<CassandraHost, HClientPool> pooldictionary = new Dictionary<CassandraHost, HClientPool>();
            foreach (HClientPool p in pools)
            {
                pooldictionary.Add(p.CassandraHost, p);
            }
            if (excludeHosts != null)
            {
                foreach (CassandraHost host in excludeHosts)
                {
                    if (pooldictionary.ContainsKey(host))
                    {
                        pooldictionary.Remove(host);
                    }
                }
            }
            List<HClientPool> sublist = new List<HClientPool>(pooldictionary.Values);
            return GetPoolSafely(sublist);
        }
        private HClientPool GetPoolSafely(List<HClientPool> pools)
        {
            HClientPool pool = pools[getAndIncrement(pools.Count)];
            logger.Info(" -------- " + pool.CassandraHost.Ip + " -------------" );
            return pool;
        }
		public virtual HClientPool CreateConnection(HClientFactory clientFactory, CassandraHost host, CassandraClientMonitor monitor)
		{
			return new ConcurrentHClientPool(clientFactory, host, monitor);
		}
	}
}